package com.example.test;

import org.openhitls.crypto.HMAC;
import org.junit.Test;
import static org.junit.Assert.*;

public class HMACTest {
    
    private void printHex(byte[] data) {
        if (data == null) {
            System.out.println("NULL");
            return;
        }
        for (byte b : data) {
            System.out.printf("%02x", b);
        }
        System.out.println();
    }
    
    @Test
    public void testHMACSM3SingleShot() {
        System.out.println("\nRunning testHMACSM3SingleShot");
        String key = "TestKey123";
        String message = "Hello, HMAC-SM3!";
        
        System.out.println("Key: " + key);
        System.out.println("Message: " + message);
        
        byte[] mac = HMAC.compute(HMAC.HMAC_SM3, key.getBytes(), message.getBytes());
        assertNotNull("MAC should not be null", mac);
        
        System.out.println("MAC: ");
        printHex(mac);
        
        assertEquals("MAC length should be 32 bytes", 32, mac.length);
    }
    
    @Test
    public void testHMACSM3Incremental() {
        System.out.println("\nRunning testHMACSM3Incremental");
        String key = "TestKey123";
        HMAC hmac = new HMAC(HMAC.HMAC_SM3, key.getBytes());
        
        String part1 = "Hello, ";
        String part2 = "HMAC-SM3!";
        
        System.out.println("Key: " + key);
        System.out.println("Part1: " + part1);
        System.out.println("Part2: " + part2);
        
        hmac.update(part1.getBytes());
        hmac.update(part2.getBytes());
        byte[] incrementalMac = hmac.doFinal();
        assertNotNull("Incremental MAC should not be null", incrementalMac);
        
        System.out.println("Incremental MAC: ");
        printHex(incrementalMac);
        
        byte[] singleMac = HMAC.compute(HMAC.HMAC_SM3, key.getBytes(), 
            (part1 + part2).getBytes());
        assertNotNull("Single-shot MAC should not be null", singleMac);
        
        System.out.println("Single-shot MAC: ");
        printHex(singleMac);
        
        assertArrayEquals(singleMac, incrementalMac);
    }
    
    @Test
    public void testEmptyString() {
        System.out.println("\nRunning testEmptyString");
        String key = "TestKey123";
        System.out.println("Key: " + key);
        
        byte[] mac = HMAC.compute(HMAC.HMAC_SM3, key.getBytes(), new byte[0]);
        assertNotNull("MAC of empty string should not be null", mac);
        
        System.out.println("MAC of empty string: ");
        printHex(mac);
        
        assertEquals("MAC length should be 32 bytes", 32, mac.length);
    }
    
    @Test
    public void testEmptyKey() {
        System.out.println("\nRunning testEmptyKey");
        String message = "Test message";
        System.out.println("Message: " + message);
        
        byte[] mac = HMAC.compute(HMAC.HMAC_SM3, new byte[0], message.getBytes());
        assertNotNull("MAC with empty key should not be null", mac);
        
        System.out.println("MAC with empty key: ");
        printHex(mac);
        
        assertEquals("MAC length should be 32 bytes", 32, mac.length);
    }
    
    @Test
    public void testReinit() {
        System.out.println("\nRunning testReinit");
        String key = "TestKey123";
        String message = "Test message";
        HMAC hmac = new HMAC(HMAC.HMAC_SM3, key.getBytes());
        
        System.out.println("Key: " + key);
        System.out.println("Message: " + message);
        
        hmac.update(message.getBytes());
        byte[] mac1 = hmac.doFinal();
        assertNotNull("First MAC should not be null", mac1);
        
        System.out.println("Original MAC: ");
        printHex(mac1);
        
        hmac.reinit();
        hmac.update(message.getBytes());
        byte[] mac2 = hmac.doFinal();
        assertNotNull("Second MAC should not be null", mac2);
        
        System.out.println("After reinit MAC: ");
        printHex(mac2);
        
        assertArrayEquals("Reinitialized HMAC should produce same result", mac1, mac2);
    }
    
    @Test
    public void testMultiThread() throws InterruptedException {
        System.out.println("\nRunning testMultiThread");
        final String key = "TestKey123";
        final String message = "Test message";
        final byte[] expectedMac = HMAC.compute(HMAC.HMAC_SM3, key.getBytes(), message.getBytes());
        assertNotNull("Expected MAC should not be null", expectedMac);
        
        System.out.println("Key: " + key);
        System.out.println("Message: " + message);
        System.out.println("Expected MAC: ");
        printHex(expectedMac);
        
        Thread[] threads = new Thread[2];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    byte[] mac = HMAC.compute(HMAC.HMAC_SM3, key.getBytes(), message.getBytes());
                    assertNotNull("Thread MAC should not be null", mac);
                    assertArrayEquals("MAC should be consistent across threads", expectedMac, mac);
                }
            });
            threads[i].start();
        }
        
        for (Thread thread : threads) {
            thread.join();
        }
    }
} 